
/*
  The contents of this file are subject to the Mozilla Public License Version
  1.1 (the "License"); you may not use this file except in compliance with
  the License. You may obtain a copy of the License at 
  http://www.mozilla.org/MPL/ 
  
  Software distributed under the License is distributed on an "AS IS" basis,
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  for the specific language governing rights and limitations under the License. 
  
  The Original Code is core2: ECMAScript core objects 2nd gig. 
  
  The Initial Developer of the Original Code is
  Zwetan Kjukov <zwetan@gmail.com>.
  Portions created by the Initial Developer are Copyright (C) 2003-2007
  the Initial Developer. All Rights Reserved.
  
  Contributor(s):
*/

var self = this;
 
if( !self.buRRRn )
    {
    /* Namespace: buRRRn
       This is the folder and namespace
       containing all the libraries and frameworks
       released by buRRRn.
    */
    self.buRRRn = {};
    }

if( !buRRRn.core2 )
    {
    /* Namespace: core2
    */
    buRRRn.core2 = {};
    }

/* Property: version
   Contains core2 version.
*/
buRRRn.core2.version = "1.1.0." + parseInt( "$Rev: 131 $".split( " " )[1] );;
 
/* Property: config
   Contains core2 configuration options.
*/
buRRRn.core2.config = {};

/* Property: CRLF
   define the Carriage Return for the environment.
*/
buRRRn.core2.config.CRLF = "\n";

/* Property: backwardCompatible
   Makes core v1.1.*+ backward compatible with core v1.0.
*/
buRRRn.core2.config.backwardCompatible = false;

/* Property: showInfo
   Allow to show core2 config at frist run.
*/
buRRRn.core2.config.showInfo = false;

/* Property: fixGetYear
   Boolean property to patch or not
   the <Date.prototype.getYear> method.
   
   see:
   JavaScript getYear returns "100" for 2000
   <https://bugzilla.mozilla.org/show_bug.cgi?id=22964>
   
   deprecated:
   _global.$CORE2_FIXGETYEAR
*/
buRRRn.core2.config.fixGetYear = false;

/* Property: errorCtor
   Boolean property to define or override
   the <Error> Object constructor.
   
   deprecated:
   _global.$CORE2_ERROR_CTOR
*/
buRRRn.core2.config.errorCtor = false;

/* Property: allowToSource
   Boolean property to define
   the toSource method in core objects.
   
   note:
   the serialization methods has been
   moved to eden, but for backward compatibility sake
   (or maybe just because you liked it ;))
   you can put back those methods in the prototype.
*/
buRRRn.core2.config.allowToSource = false;

/* Property: opAsTopLevel
   Boolean option to allow to make operators function
   as top level function
   
   ex:
   (code)
   //opAsTopLevel = true;
   if( is(something)(String) )
       {
       trace( "found a string" );
       } 
   (end)
*/
buRRRn.core2.config.opAsTopLevel = false;


/* Property: globalsReserved
   List of global reserved keywords.
*/
buRRRn.core2.config.globalsReserved = [ "_global" ];

/* Property: host
   Contains the host name.
   
   note:
   host can be
   Unknown - host has not been found
   WSH     - Windows Script host
   JSDB    - JavaScript for DataBase
   Browser - Browsers (MSIE, Firefox, Opera, Safari, etc.)
   Flash   - Flash player
*/
buRRRn.core2.config.host = "";

/* Property: hostMoreInfo
   Contains more info (build and/or version etc.)
   about the host environment.
*/
buRRRn.core2.config.hostMoreInfo = "";

/* Property: language
   Contains the ECMAScript language breed.
   
   note:
   language can be
   ECMAScript - by default
   JavaScript - SpiderMonkey or any other engine in the browser
   JScript    - Microsoft engine
*/
buRRRn.core2.config.language = "";

/* Property: languageMoreInfo
   Contains the version of the language if found.
*/
buRRRn.core2.config.languageMoreInfo = "";


/* Property: strings
   Contains core2 resource strings.
*/
buRRRn.core2.strings = {};

buRRRn.core2.strings.hostNotFound = "Host not found";
buRRRn.core2.strings.message = "";

/*Method: getString
  Gets the resource string contained in name
  or the empty string if not found.
*/
buRRRn.core2.getString = function( name/*String*/ )/*String*/
    {
    if( !this.strings[name] )
        {
        return "";
        }
    
    return this.strings[name];
    }

/* Method: isGlobalReserved
   Returns a Boolean that indicates if the
   supplied name keyword is reserved or not.
*/
buRRRn.core2.isGlobalReserved = function( name/*String*/ )/*Boolean*/
    {
    var words = this.config.globalsReserved.join( "|" );
    if( words.indexOf( name ) > -1 )
        {
        return true;
        }
    
    return false;
    }

buRRRn.core2.addReserved = function( name/*String*/ )
    {
    var words = this.config.globalsReserved.join("|");
    
    var contains = function( word/*String*/ )
        {
        return words.indexOf( word ) > -1;
        }
    
    if( !contains( name ) )
        {
        this.config.globalsReserved.push( name );
        }
    }

/* Method: introspectEnvironment
*/
buRRRn.core2.introspectEnvironment = function()
    {
    var env = { host:"", lang:"" };
    
    if( (this.config.host != "") &&
        (this.config.language != "") )
        {
        env.host = this.config.host;
        env.lang = this.config.language;
        return env;
        }

    if( (typeof WSH != "undefined") || (typeof WScript != "undefined") )
        {
        env.host = "WSH";
        env.lang = "JScript";
        this.config.hostMoreInfo     = WScript.Version;
        this.config.languageMoreInfo = ScriptEngineMajorVersion()+"."+ScriptEngineMinorVersion()+"."+ScriptEngineBuildVersion();
        }
    
    if( (typeof Server != "undefined") || (typeof Stream != "undefined") || (typeof ActiveX != "undefined") )
        {
        env.host = "JSDB";
        env.lang = "JavaScript";
        this.config.hostMoreInfo     = "build " + system.buildDate;
        this.config.languageMoreInfo = system.version/100;
        }
    
    if( (typeof $version != "undefined") || (typeof MovieClip != "undefined") )
        {
        env.host = "Flash";
        env.lang = "ActionScript";
        
        this.config.hostMoreInfo = $version;
        }
    
    if( (typeof document != "undefined") || (typeof window != "undefined") ||
        (typeof navigator != "undefined") || (typeof location != "undefined") )
        {
        env.host = "Browser";
        env.lang = "JavaScript";
        
        if( navigator.userAgent.indexOf("MSIE") != -1 )
            {
            this.config.hostMoreInfo = "MSIE";
            env.lang = "JScript";
            this.config.languageMoreInfo = ScriptEngineMajorVersion()+"."+ScriptEngineMinorVersion()+"."+ScriptEngineBuildVersion();
            }
        else if( navigator.userAgent.indexOf("Firefox") != -1 )
            {
            this.config.hostMoreInfo = "Firefox";
            }
        else if( navigator.userAgent.indexOf("Opera") != -1 )
            {
            this.config.hostMoreInfo = "Opera";
            }
        else if( navigator.userAgent.indexOf("AppleWebKit") != -1 )
            {
            this.config.hostMoreInfo = "Safari";
            }
        
        if( location.href.split( "." ).pop() == "hta" )
            {
            this.config.hostMoreInfo = "MSIE HTA";
            }
        
        }
    
    if( (env.host == "") || (env.lang == "") )
        {
        env.host = "Unknown";
        env.lang = "ECMAScript";
        trace( "## WARNING : " + this.strings.hostNotFound + " ##" );
        }
    
    this.config.host     = env.host;
    this.config.language = env.lang;
    return env;
    }

/* Method: getHost
   Returns the host name.
*/
buRRRn.core2.getHost = function()
    {
    if( this.config.host != "" )
        {
        return this.config.host;
        }
    
    var env = this.introspectEnvironment();
    return env.host;
    }

/* Method: getLanguage
   Returns the language breed.
*/
buRRRn.core2.getLanguage = function()
    {
    if( this.config.language != "" )
        {
        return this.config.language;
        }
    
    var env = this.introspectEnvironment();
    return env.lang;
    }

/* Method: hasFunctionSource
   Returns a Boolean to indicate if the host support
   to retrieve the body of a function as string.
   
   deprecated:
   _global.$CORE2_FCTNSTRING
*/
buRRRn.core2.hasFunctionSource = function()
    {
    
    var test = function()
        {
        return "true";
        }
    
    return test.toString().indexOf( "return \"true\";" ) > 0;
    }

/* Method: introspectGlobal
   Scan browser defined globals
   and store them in <globalsReserved>.
   
   note:
   We need to do that to avoid "too much recursion errors"
   inside browsers when we do code introspection.
*/
buRRRn.core2.introspectGlobal = function()
    {
    switch( this.getHost() )
        {
        case "JSDB":
        break;
        
        case "WSH":
        this.addReserved( "WSH" );
        this.addReserved( "WScript" );
        break;
        
        case "Browser":
        this.addReserved( "document" );
        this.addReserved( "window" );
        this.addReserved( "navigator" );
        this.addReserved( "location" );
        
        for( var o in self )
            {
            
            if( (o == "buRRRn") || (o == "core2") || (o == "_global") )
                {
                continue;
                }
            
            this.addReserved( o );
            }
        
        break;
        }
    }

/* Method: infos
   Traces core2 informations.
*/
buRRRn.core2.infos = function()
    {
    var hostmi = "";
    var langmi = "";
    
    if( this.config.hostMoreInfo != "" )
        {
        hostmi = " ( " + this.config.hostMoreInfo + " )";
        }
    
    if( this.config.languageMoreInfo != "" )
        {
        langmi = " v" + this.config.languageMoreInfo;
        }
    
    trace( "core2 v"+this.version );
    trace( "-- Environment --" );
    trace( "hasFunctionSource:  " + this.hasFunctionSource() );
    trace( "host:               " + this.getHost() + hostmi );
    trace( "language:           " + this.getLanguage() + langmi );
    
    trace( "-- Configuration options --" );
    trace( "backwardCompatible: " + this.config.backwardCompatible );
    trace( "showInfo:           " + this.config.showInfo );
    trace( "fixGetYear:         " + this.config.fixGetYear );
    trace( "errorCtor:          " + this.config.errorCtor );
    trace( "allowToSource:      " + this.config.allowToSource );
    trace( "opAsTopLevel:       " + this.config.opAsTopLevel );
    
    trace( "globalsReserved:   [" + this.config.globalsReserved + "]" );
    
    }

/* Method: setTrace
   Override the trace function.
*/
buRRRn.core2.setTrace = function( traceFunction/*Function*/ )
    {
    _global.trace = function( o )
        {
        traceFunction( o );
        }
    
    //flush message
    if( this.strings.message != "" )
        {
        trace( this.strings.message );
        this.strings.message = "";
        }
    }

/* Method: main
   Execute the core2 main entry point.
   
   note:
   general object namespace structure
   
   (code)
   {namespace}
          |_ config
          |      |_ option1
          |      |_ option2
          |      |_ etc.
          |      |_ strings
          |            |_ resource_string1
          |            |_ resource_string2
          |            |_ etc.
          |_ utilityMethod1
          |_ utilityMethod2
          |_ etc.
          |_ main
   (end)
   
   *core2.config*
   store configuration options
   
   ex:
   (code)
   //before
   if( $CORE2_FIXGETYEAR )
       {
       //...
       }
   
   //after
   if( core2.config.fixGetYear )
       {
       //...
       }
   (end)
   
   *core2.config.strings*
   store resource strings
   
   ex:
   (code)
   if( this.getHost() == "Unknown" )
       {
       trace( this.getString( "hostNotFound" ) );
       }
   (end)
   
*/
buRRRn.core2.main = function()
    {
    this.introspectEnvironment();
    this.introspectGlobal();
    
    switch( this.getHost() )
        {
        case "WSH":
        self._global = self;
        delete self;
        this.config.errorCtor = false;
        this.config.CRLF = "\n";
        
        _global.trace = function( o )
            {
            WScript.Echo( String( o ) );
            }
        
        break;
        
        case "JSDB":
        self._global = self;
        delete self;
        this.config.errorCtor = false;
        this.config.CRLF = "\n";
        
        _global.trace = function( o  )
            {
            writeln( String( o ) );
            }
        
        break;
        
        case "Flash":
        _global.buRRRn = self.buRRRn;
        delete self;
        this.config.errorCtor = true;
        this.config.CRLF = "\n";
        
        Object.prototype.propertyIsEnumerable = Object.prototype.isPropertyEnumerable;
        //use ASPF
        break;
        
        case "Browser":
        self._global = self;
        delete self;
        this.config.errorCtor = false;
        this.config.CRLF = "\r\n";
        
        if( this.config.hostMoreInfo == "Firefox" )
            {
            this.config.CRLF = "\n";
            }
        
        _global.trace = function( o )
            {
            buRRRn.core2.strings.message += String( o + buRRRn.core2.config.CRLF );
            }
        
        break;
        
        case "Unknown":
        default:
        }
    
    }

buRRRn.core2._changeCompatibility = function()
    {
    
    if( this.config.backwardCompatible )
        {
        _global.GetTypeOf = buRRRn.Reflection.getTypeOf;
        _global.GetObjectPath = function( o )
            {
            return buRRRn.Reflection.getObjectPath( o );
            }
        }
    else
        {
        if( _global.GetTypeOf )
            {
            delete _global.GetTypeOf;
            }
        
        if( _global.GetObjectPath )
            {
            delete _global.GetObjectPath;
            }
        }
    
    }

buRRRn.core2._changeToSource = function()
    {
    
    if( this.config.backwardCompatible && this.config.allowToSource )
        {
        Boolean.prototype.toSource = function()
            {
            return (this == true) ? "true": "false";
            }
        
        Number.prototype.toSource = function()
            {
            return this.toString();
            }
        
        Function.prototype.toSource = function()
            {
            return "(function)";
            }
                
        String.prototype.toSource = function()
            {
            return buRRRn.eden.Serializer.emitString( this );
            }        
        
        Object.prototype.toSource = function()
            {
            return buRRRn.eden.Serializer.emitObject( this );
            }
        
        Array.prototype.toSource = function()
            {
            return buRRRn.eden.Serializer.emitArray( this );
            }
        
        Date.prototype.toSource = function()
            {
            return buRRRn.eden.Serializer.emitDate( this );
            }
        
        Error.prototype.toSource = function()
            {
            return "new Error(\""+this.message+"\")";
            }
        
        _global.ToSource = function()
            {
            return buRRRn.eden.Serializer.emitGlobal( _global );
            }
        
        }
    else
        {
        if( Boolean.prototype.toSource )
            {
            delete Boolean.prototype.toSource;
            }
        
        if( Number.prototype.toSource )
            {
            delete Number.prototype.toSource;
            }
        
        if( Function.prototype.toSource )
            {
            delete Function.prototype.toSource;
            }
        
        if( String.prototype.toSource )
            {
            delete String.prototype.toSource;
            }
        
        if( Object.prototype.toSource )
            {
            delete Object.prototype.toSource;
            }
        
        if( Array.prototype.toSource )
            {
            delete Array.prototype.toSource;
            }
        
        if( Date.prototype.toSource )
            {
            delete Date.prototype.toSource;
            }
        
        if( Error.prototype.toSource )
            {
            delete Error.prototype.toSource;
            }
        
        if( _global.ToSource )
            {
            delete _global.ToSource;
            }
        
        }
    
    }

buRRRn.core2._changeOperators = function()
    {
    if( this.config.opAsTopLevel )
        {
        _global.is = function( o )
            {
            return buRRRn.core2.operators.is( o );
            }
        }
    else
        {
        if( _global.is )
            {
            delete _global.is;
            }
        
        }
    }

/* Method: after
   Execute after the main function,
   for cases where you can not or don't want to execute
   within the main function.
*/
buRRRn.core2.after = function()
    {
    
    //operators
    this._changeOperators();
    
    //compatibility
    this._changeCompatibility();
    
    //toSource
    this._changeToSource();
    
    if( this.config.showInfo )
        {
        this.infos();
        }
    }

/* Method: changeConfig
   Allows to dynamically change the core2 configuration.
   
   usage:
   (code)
   buRRRn.core2.changeConfig( {backwardCompatible:true,allowToSource:true} );
   //core v1.0 code here
   buRRRn.core2.changeConfig( {backwardCompatible:false,allowToSource:false} );
   //core2 v1.1 code here, no more function in _global, etc.
   (end)
*/
buRRRn.core2.changeConfig = function( options/*Object*/ )
    {
    
    if( options.backwardCompatible && (options.backwardCompatible != this.config.backwardCompatible) )
        {
        this.config.backwardCompatible = options.backwardCompatible;
        this._changeCompatibility();
        
        if( options.allowToSource && (options.allowToSource != this.config.allowToSource) )
            {
            this.config.allowToSource = options.allowToSource;
            this._changeToSource();
            }
        
        }
    
    }

/* note:
   ActionScript does not support the construct
   core.main = function()
       {
       //...
       }(); //autoexecute
   so for compatibility sake we don't use that construct
   
   Also some ECMAScript implementation can not use
   the 'this' keyword inside such auto-executed function.
*/
buRRRn.core2.main(); //autoexecute
